import re
import os
import argparse
import shutil
import json
import logging
from typing import Dict, List, Tuple, Optional
from dataclasses import dataclass, asdict
from collections import defaultdict

@dataclass
class Change:
    """追踪文本修改的类"""
    original: str  # 原始标点
    fixed: str     # 修复后的标点
    position: int  # 在文本中的位置
    context: str   # 上下文
    line: int      # 行号
    
    def to_dict(self):
        """将对象转换为字典，用于JSON序列化"""
        return asdict(self)

class PunctuationFixer:
    def __init__(self, custom_mapping: Dict = None, ignore_patterns: List[str] = None, config_file: str = None):
        """
        初始化标点符号修复器
        
        参数：
            custom_mapping: 自定义标点映射字典
            ignore_patterns: 额外需要忽略的模式
            config_file: 配置文件路径
        """
        # 默认中英文标点映射（中文到英文）
        self.cn_to_en_mapping = {
            "，": ",",
            "。": ".",
            "；": ";",
            "：": ":",
            """: "\"",
            """: "\"",
            "'": "'",
            "'": "'",
            "（": "(",
            "）": ")",
            "、": ",",
            "！": "!",
            "？": "?",
            "【": "[",
            "】": "]",
            "《": "<",
            "》": ">"
        }
        
        # 从配置文件加载设置（如果提供）
        if config_file and os.path.exists(config_file):
            self._load_config(config_file)
        
        # 如果提供了自定义映射，则更新默认映射
        if custom_mapping:
            self.cn_to_en_mapping.update(custom_mapping)
        
        # 创建逆向映射（英文到中文）
        self.en_to_cn_mapping = {v: k for k, v in self.cn_to_en_mapping.items()}
        
        # 特殊需要忽略的模式
        self.special_ignore_patterns = [
            # 英文缩写和引用
            r'e\.g\.',        # e.g.
            r'i\.e\.',        # i.e.
            r'et\s+al\.',     # et al.
            r'etc\.',         # etc.
            r'vs\.',          # vs.
            r'viz\.',         # viz.
            r'cf\.',          # cf.
            r'p\.\s*\d+',     # p. 123
            r'pp\.\s*\d+',    # pp. 123
            r'fig\.\s*\d+',   # fig. 1
            r'figure\s*\d+\.?', # figure 1 or figure 1.
            r'tab\.\s*\d+',   # tab. 1
            r'table\s*\d+\.?', # table 1 or table 1.
            r'eq\.\s*\d+',    # eq. 1
            r'equation\s*\d+\.?', # equation 1 or equation 1.
            r'ref\.\s*\d+',   # ref. 1
            r'sec\.\s*\d+',   # sec. 1
            r'chap\.\s*\d+',  # chap. 1
            r'vol\.\s*\d+',   # vol. 1
            r'no\.\s*\d+',    # no. 1
            
            # 中文引用
            r'图\s*\d+',      # 图1 or 图 1
            r'表\s*\d+',      # 表1 or 表 1
            r'公式\s*\d+',    # 公式1 or 公式 1
            r'参考文献\s*\d+', # 参考文献1 or 参考文献 1
            r'章\s*\d+',      # 章1 or 章 1
            r'节\s*\d+',      # 节1 or 节 1
            r'页\s*\d+',      # 页1 or 页 1
            
            # 常见缩写
            r'[A-Z]\.', # 单字母缩写 (e.g., A., B., ...)
            r'[A-Z]\.[A-Z]\.', # 双字母缩写 (e.g., U.S., U.K., ...)
            r'[A-Z]\.[A-Z]\.[A-Z]\.', # 三字母缩写 (e.g., U.S.A., ...)
            r'Ph\.D\.', r'M\.Sc\.', r'B\.Sc\.', r'M\.A\.', r'B\.A\.',
            r'Dr\.', r'Prof\.', r'Mr\.', r'Mrs\.', r'Ms\.',
            r'Jr\.', r'Sr\.', r'Co\.', r'Inc\.', r'Ltd\.',
            
            # 网址和邮箱
            r'https?://[^\s]+', # URLs
            r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}', # Email
        ]
        
        # 添加用户提供的模式
        if ignore_patterns:
            self.special_ignore_patterns.extend(ignore_patterns)
        
        # 识别LaTeX元素的模式
        self.latex_patterns = [
            r'\\[a-zA-Z]+(\[[^\]]*\])?(\{[^}]*\})*',  # 命令如 \section{}, \textbf{}
            r'\\begin\{[^}]*\}.*?\\end\{[^}]*\}',     # 环境如 \begin{...}...\end{...}
            r'\$\$.*?\$\$',                           # 显示数学公式 $$...$$
            r'\$.*?\$',                               # 行内数学公式 $...$
            r'\\[\[\(].*?\\[\]\)]',                   # 数学公式 \[...\] 或 \(...\)
            r'%.*?$',                                 # 注释 %...
            r'\\cite\{[^}]*\}',                       # 引用 \cite{...}
            r'\\ref\{[^}]*\}',                        # 引用 \ref{...}
            r'\\label\{[^}]*\}',                      # 标签 \label{...}
            r'\\url\{[^}]*\}',                        # URL \url{...}
            r'\\href\{[^}]*\}\{[^}]*\}',              # 超链接 \href{...}{...}
            r'\\verb\|.*?\|',                         # 原样文本 \verb|...|
            r'\\verb\!.*?\!',                         # 原样文本其他分隔符
            r'\\verb\#.*?\#',
            r'\\verb\+.*?\+',
            r'\\verb\=.*?\=',
        ]
        
        # 编译正则表达式
        self.latex_regex = re.compile('|'.join(self.latex_patterns), re.DOTALL | re.MULTILINE)
        self.special_ignore_regex = re.compile('|'.join(self.special_ignore_patterns), re.IGNORECASE)
        
        # 设置日志记录器
        self.logger = logging.getLogger('PunctuationFixer')
        self.logger.setLevel(logging.INFO)
        if not self.logger.handlers:
            handler = logging.StreamHandler()
            formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
            handler.setFormatter(formatter)
            self.logger.addHandler(handler)
    
    def _load_config(self, config_file: str) -> None:
        """从JSON文件加载配置"""
        try:
            with open(config_file, 'r', encoding='utf-8') as f:
                config = json.load(f)
            
            # 更新标点映射
            if 'punctuation_mapping' in config:
                self.cn_to_en_mapping.update(config['punctuation_mapping'])
            
            # 更新忽略模式
            if 'ignore_patterns' in config:
                self.special_ignore_patterns.extend(config['ignore_patterns'])
            
            self.logger.info(f"从{config_file}加载了配置")
        except Exception as e:
            self.logger.error(f"从{config_file}加载配置时出错: {e}")
    
    def _count_newlines(self, text: str, position: int) -> int:
        """计算指定位置前的换行符数量（确定行号）"""
        return text[:position].count('\n') + 1
    
    def _is_chinese_char(self, char: str) -> bool:
        """检查字符是否为中文字符"""
        if len(char) != 1:
            return False
        
        # 检查字符是否在CJK统一汉字范围内
        if 0x4E00 <= ord(char) <= 0x9FFF:
            return True
        
        # 检查其他CJK区块
        cjk_blocks = [
            (0x3400, 0x4DBF),   # CJK统一汉字扩展A
            (0x20000, 0x2A6DF), # CJK统一汉字扩展B
            (0x2A700, 0x2B73F), # CJK统一汉字扩展C
            (0x2B740, 0x2B81F), # CJK统一汉字扩展D
            (0xF900, 0xFAFF),   # CJK兼容汉字
        ]
        
        for start, end in cjk_blocks:
            if start <= ord(char) <= end:
                return True
        
        return False
    
    def _is_english_char(self, char: str) -> bool:
        """检查字符是否为英文字符(a-z, A-Z)"""
        if len(char) != 1:
            return False
        return char.isalpha() and ord(char) < 128
    
    def _get_surrounding_text(self, text: str, position: int, window: int = 20) -> str:
        """获取上下文文本"""
        start = max(0, position - window)
        end = min(len(text), position + window)
        context = text[start:end]
        
        if start > 0:
            context = '...' + context
        if end < len(text):
            context = context + '...'
            
        return context
    
    def _protect_latex_and_special(self, text: str) -> Tuple[str, List[Tuple[str, str, int]]]:
        """
        识别并保护LaTeX元素和特殊模式，使用占位符替换它们。
        返回修改后的文本和(占位符,原始文本,位置)元组列表。
        """
        protected_elements = []
        
        # 首先，保护特殊模式，如"e.g.", "i.e."等
        special_matches = list(self.special_ignore_regex.finditer(text))
        for match in reversed(special_matches):  # 反向处理以保持位置
            start, end = match.span()
            placeholder = f"__SPECIAL_{len(protected_elements)}__"
            protected_elements.append((placeholder, match.group(0), start))
            text = text[:start] + placeholder + text[end:]
        
        # 然后保护LaTeX元素
        latex_matches = list(self.latex_regex.finditer(text))
        for match in reversed(latex_matches):  # 反向处理以保持位置
            start, end = match.span()
            placeholder = f"__LATEX_{len(protected_elements)}__"
            protected_elements.append((placeholder, match.group(0), start))
            text = text[:start] + placeholder + text[end:]
        
        return text, protected_elements
    
    def _restore_protected(self, text: str, protected_elements: List[Tuple[str, str, int]]) -> str:
        """恢复原始受保护的元素"""
        for placeholder, original, _ in protected_elements:
            text = text.replace(placeholder, original)
        return text
    
    def _analyze_language_context(self, text: str, position: int, window: int = 10) -> str:
        """
        分析文本特定位置周围的语言环境。
        返回'cn'表示中文环境，'en'表示英文环境。
        """
        # 获取周围文本
        start = max(0, position - window)
        end = min(len(text), position + window)
        context = text[start:end]
        
        # 计算中文和英文字符数
        chinese_count = sum(1 for char in context if self._is_chinese_char(char))
        english_count = sum(1 for char in context if self._is_english_char(char))
        
        # 如果中文字符明显更多，则为中文环境
        if chinese_count > english_count * 1.5:
            return 'cn'
        # 如果英文字符明显更多，则为英文环境
        elif english_count > chinese_count * 1.5:
            return 'en'
        # 如果混合或不清楚，查看紧邻位置的字符
        else:
            # 找到位置前最近的非空白字符
            pre_char = None
            for i in range(position - 1, max(0, position - 5), -1):
                if i < len(text) and not text[i].isspace():
                    pre_char = text[i]
                    break
            
            # 找到位置后最近的非空白字符
            post_char = None
            for i in range(position, min(len(text), position + 5)):
                if i < len(text) and not text[i].isspace():
                    post_char = text[i]
                    break
            
            # 如果周围字符都是中文，则为中文环境
            if pre_char and post_char and self._is_chinese_char(pre_char) and self._is_chinese_char(post_char):
                return 'cn'
            # 如果周围字符都是英文，则为英文环境
            elif pre_char and post_char and self._is_english_char(pre_char) and self._is_english_char(post_char):
                return 'en'
            # 如果混合或不清楚，默认为中文
            else:
                return 'cn'
    
    def fix_text(self, text: str) -> Tuple[str, List[Change]]:
        """
        处理整个文本以根据语言环境修复标点符号。
        返回修复后的文本和Change对象列表。
        """
        changes = []
        
        # 步骤1：保护LaTeX元素和特殊模式
        protected_text, protected_elements = self._protect_latex_and_special(text)
        
        # 步骤2：修复标点符号
        fixed_text = protected_text
        
        # 处理英文环境中的中文标点
        for cn_punct, en_punct in self.cn_to_en_mapping.items():
            # 找到所有中文标点出现位置
            for match in re.finditer(re.escape(cn_punct), fixed_text):
                pos = match.start()
                context = self._analyze_language_context(fixed_text, pos)
                
                if context == 'en':
                    # 在英文环境中将中文标点替换为英文
                    original_context = self._get_surrounding_text(fixed_text, pos)
                    line_number = self._count_newlines(fixed_text, pos)
                    
                    fixed_text = fixed_text[:pos] + en_punct + fixed_text[pos+len(cn_punct):]
                    
                    changes.append(Change(
                        original=cn_punct,
                        fixed=en_punct,
                        position=pos,
                        context=original_context,
                        line=line_number
                    ))
        
        # 处理中文环境中的英文标点
        for en_punct, cn_punct in self.en_to_cn_mapping.items():
            # 找到所有英文标点出现位置
            for match in re.finditer(re.escape(en_punct), fixed_text):
                pos = match.start()
                context = self._analyze_language_context(fixed_text, pos)
                
                if context == 'cn':
                    # 在中文环境中将英文标点替换为中文
                    original_context = self._get_surrounding_text(fixed_text, pos)
                    line_number = self._count_newlines(fixed_text, pos)
                    
                    fixed_text = fixed_text[:pos] + cn_punct + fixed_text[pos+len(en_punct):]
                    
                    changes.append(Change(
                        original=en_punct,
                        fixed=cn_punct,
                        position=pos,
                        context=original_context,
                        line=line_number
                    ))
        
        # 步骤3：恢复受保护元素
        final_text = self._restore_protected(fixed_text, protected_elements)
        
        return final_text, changes
    
    def preview_changes(self, text: str) -> str:
        """
        生成将要进行的更改预览。
        返回带有高亮更改的字符串。
        """
        _, changes = self.fix_text(text)
        
        if not changes:
            return "不需要进行任何更改。"
        
        preview_lines = []
        preview_lines.append(f"预览 {len(changes)} 处更改:")
        preview_lines.append("")
        
        # 按行号分组更改
        changes_by_line = defaultdict(list)
        for change in changes:
            changes_by_line[change.line].append(change)
        
        # 处理每一行的更改
        for line_number, line_changes in sorted(changes_by_line.items()):
            preview_lines.append(f"第 {line_number} 行:")
            
            # 显示上下文中的原始和修复后的标点
            for change in line_changes:
                preview_lines.append(f"  原始: {change.context}")
                # 高亮修复后的标点
                fixed_context = change.context.replace(change.original, f"[{change.fixed}]", 1)
                preview_lines.append(f"  修复: {fixed_context}")
                preview_lines.append("")
        
        return "\n".join(preview_lines)
    
    def process_file(self, input_file: str, output_file: str = None, backup: bool = True, preview_only: bool = False) -> Dict:
        """
        处理单个文件并保存结果。
        返回包含有关所做更改统计信息的字典。
        
        参数:
            input_file: 输入文件路径
            output_file: 输出文件路径(如果为None，则覆盖输入文件)
            backup: 是否创建输入文件的备份
            preview_only: 如果为True，仅预览更改而不实际进行
        """
        self.logger.info(f"处理文件: {input_file}")
        
        # 读取输入文件
        try:
            with open(input_file, 'r', encoding='utf-8') as f:
                content = f.read()
        except UnicodeDecodeError:
            self.logger.warning(f"文件 {input_file} 不是UTF-8编码，尝试使用系统默认编码")
            with open(input_file, 'r') as f:
                content = f.read()
        
        # 如果仅预览，生成并返回预览
        if preview_only:
            preview = self.preview_changes(content)
            return {
                'input_file': input_file,
                'preview': preview
            }
        
        # 如果请求，创建备份
        if backup:
            backup_file = input_file + '.bak'
            shutil.copy2(input_file, backup_file)
            self.logger.info(f"已创建备份: {backup_file}")
        
        # 修复标点
        fixed_content, changes = self.fix_text(content)
        
        # 保存修复后的内容
        if output_file:
            output_path = output_file
        else:
            output_path = input_file
        
        with open(output_path, 'w', encoding='utf-8') as f:
            f.write(fixed_content)
        
        self.logger.info(f"修复后的内容已保存到: {output_path}")
        self.logger.info(f"总共进行了 {len(changes)} 处更改")
        
        # 准备统计信息
        stats = {
            'input_file': input_file,
            'output_file': output_path,
            'total_changes': len(changes),
            'changes': changes
        }
        
        return stats
    
    def process_files(self, input_files: List[str], output_dir: str = None, backup: bool = True, preview_only: bool = False) -> List[Dict]:
        """
        处理多个文件并保存结果。
        返回每个文件的统计字典列表。
        
        参数:
            input_files: 输入文件路径列表
            output_dir: 保存输出文件的目录(如果为None，则覆盖输入文件)
            backup: 是否创建输入文件的备份
            preview_only: 如果为True，仅预览更改而不实际进行
        """
        results = []
        
        for input_file in input_files:
            if not os.path.exists(input_file):
                self.logger.warning(f"文件未找到: {input_file}")
                continue
            
            if output_dir:
                output_file = os.path.join(output_dir, os.path.basename(input_file))
            else:
                output_file = None
            
            stats = self.process_file(input_file, output_file, backup, preview_only)
            results.append(stats)
        
        return results
    
    def generate_report(self, results: List[Dict], report_file: str = None, format: str = 'text') -> str:
        """
        生成有关对文件所做更改的报告。
        返回报告字符串，并可选择保存到文件。
        
        参数:
            results: 统计字典列表
            report_file: 保存报告的路径(如果为None，则不保存)
            format: 报告格式('text', 'markdown'或'json')
        """
        if format.lower() == 'json':
            # 将Change对象转换为字典以进行JSON序列化
            json_results = []
            for result in results:
                json_result = {k: v for k, v in result.items()}
                if 'changes' in json_result:
                    json_result['changes'] = [c.to_dict() for c in json_result['changes']]
                json_results.append(json_result)
            
            report = json.dumps(json_results, indent=2, ensure_ascii=False)
            
            if report_file:
                with open(report_file, 'w', encoding='utf-8') as f:
                    f.write(report)
                self.logger.info(f"JSON报告已保存到: {report_file}")
            
            return report
        
        # 对于text或markdown格式
        total_files = len(results)
        total_changes = sum(result.get('total_changes', 0) for result in results if 'total_changes' in result)
        
        if format.lower() == 'markdown':
            report_lines = ["# 标点符号修正报告", ""]
            report_lines.append(f"**总处理文件数:** {total_files}")
            report_lines.append(f"**总更改数:** {total_changes}")
            report_lines.append("")
            
            for result in results:
                if 'preview' in result:
                    # 这是预览结果
                    report_lines.append(f"## 预览: {result['input_file']}")
                    report_lines.append("```")
                    report_lines.append(result['preview'])
                    report_lines.append("```")
                    report_lines.append("")
                else:
                    # 这是常规结果
                    report_lines.append(f"## 文件: {result['input_file']}")
                    report_lines.append(f"**输出文件:** {result['output_file']}")
                    report_lines.append(f"**更改数:** {result['total_changes']}")
                    report_lines.append("")
                    
                    if result['total_changes'] > 0 and 'changes' in result and result['changes']:
                        report_lines.append("### 更改详情")
                        report_lines.append("")
                        report_lines.append("| 行号 | 原始 | 修复 | 上下文 |")
                        report_lines.append("|------|------|------|--------|")
                        
                        for change in result['changes']:
                            line = f"| {change.line} | {change.original} | {change.fixed} | {change.context.replace('|', '&#124;')} |"
                            report_lines.append(line)
                        
                        report_lines.append("")
        elif format.lower() == 'text':
            report_lines = ["标点符号修正报告", ""]
            report_lines.append(f"总处理文件数: {total_files}")
            report_lines.append(f"总更改数: {total_changes}")
            report_lines.append("")
            
            for result in results:
                if 'preview' in result:
                    # 这是预览结果
                    report_lines.append(f"预览: {result['input_file']}")
                    report_lines.append("-" * 60)
                    report_lines.append(result['preview'])
                    report_lines.append("-" * 60)
                    report_lines.append("")
                else:
                    # 这是常规结果
                    report_lines.append(f"文件: {result['input_file']}")
                    report_lines.append(f"输出文件: {result['output_file']}")
                    report_lines.append(f"更改数: {result['total_changes']}")
                    report_lines.append("")
                    
                    if result['total_changes'] > 0 and 'changes' in result and result['changes']:
                        report_lines.append("更改详情:")
                        report_lines.append("-" * 60)
                        
                        for change in result['changes']:
                            report_lines.append(f"行 {change.line}: '{change.original}' -> '{change.fixed}'")
                            report_lines.append(f"上下文: {change.context}")
                            report_lines.append("")
                        
                        report_lines.append("-" * 60)
                        report_lines.append("")
        
        report = "\n".join(report_lines)
        
        if report_file:
            with open(report_file, 'w', encoding='utf-8') as f:
                f.write(report)
            self.logger.info(f"报告已保存到: {report_file}")
        
        return report


def main():
    """命令行入口点"""
    parser = argparse.ArgumentParser(description='中英文混合LaTeX文档标点符号修复工具')
    
    # 输入/输出参数
    parser.add_argument('files', nargs='+', help='输入文件路径(支持通配符)')
    parser.add_argument('-o', '--output-dir', help='输出文件目录')
    parser.add_argument('-r', '--report', help='生成报告文件路径')
    parser.add_argument('--report-format', choices=['text', 'markdown', 'json'], default='text',
                        help='报告格式(text, markdown, json)')
    
    # 操作选项
    parser.add_argument('-p', '--preview', action='store_true', help='仅预览更改，不修改文件')
    parser.add_argument('-b', '--no-backup', action='store_true', help='不创建备份文件')
    parser.add_argument('-c', '--config', help='配置文件路径')
    
    # 日志选项
    parser.add_argument('--verbose', action='store_true', help='输出详细日志信息')
    parser.add_argument('--quiet', action='store_true', help='只输出错误信息')
    
    args = parser.parse_args()
    
    # 设置日志级别
    log_level = logging.INFO
    if args.verbose:
        log_level = logging.DEBUG
    elif args.quiet:
        log_level = logging.ERROR
    
    logging.basicConfig(level=log_level,
                        format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    
    logger = logging.getLogger(__name__)
    
    # 创建标点修复器
    fixer = PunctuationFixer(config_file=args.config)
    
    # 扩展文件通配符
    import glob
    input_files = []
    for file_pattern in args.files:
        matched_files = glob.glob(file_pattern)
        if matched_files:
            input_files.extend(matched_files)
        else:
            logger.warning(f"没有找到匹配的文件: {file_pattern}")
    
    if not input_files:
        logger.error("没有找到匹配的文件")
        return 1
    
    # 确保输出目录存在
    if args.output_dir and not os.path.exists(args.output_dir):
        os.makedirs(args.output_dir)
    
    # 处理文件
    results = fixer.process_files(
        input_files,
        output_dir=args.output_dir,
        backup=not args.no_backup,
        preview_only=args.preview
    )
    
    # 生成报告
    if args.report:
        report = fixer.generate_report(results, args.report, args.report_format)
    else:
        report = fixer.generate_report(results, format=args.report_format)
        print(report)
    
    logger.info(f"处理完成，共处理 {len(input_files)} 个文件")
    return 0

#
# if __name__ == "__main__":
#     exit(main())出文件:** {result['output_file']}")
#                     report_lines.append(f"**更改数:** {result['total_changes']}")
#                     report_lines.append("")
#
#                     if result['total_changes'] > 0 and 'changes' in result and result['changes']:
#                         report_lines.append("### 更改详情")
#                         report_lines.append("")
#                         report_lines.append("| 行号 | 原始 | 修复 | 上下文 |")
#                         report_lines.append("|------|------|------|--------|")
#
#                         for change in result['changes']:
#                             line = f"| {change.line} | {change.original} | {change.fixed} | {change.context.replace('|', '&#124;')} |"
#                             report_lines.append(line)
#
#                         report_lines.append("")
#         elif format.lower() == 'text':
#             report_lines = ["标点符号修正报告", ""]
#             report_lines.append(f"总处理文件数: {total_files}")
#             report_lines.append(f"总更改数: {total_changes}")
#             report_lines.append("")
#
#             for result in results:
#                 if 'preview' in result:
#                     # 这是预览结果
#                     report_lines.append(f"预览: {result['input_file']}")
#                     report_lines.append("-" * 60)
#                     report_lines.append(result['preview'])
#                     report_lines.append("-" * 60)
#                     report_lines.append("")
#                 else:
#                     # 这是常规结果
#                     report_lines.append(f"文件: {result['input_file']}")
#                     report_lines.append(f"输出文件: {result['output_file']}")
#                     report_lines.append(f"更改数: {result['total_changes']}")
#                     report_lines.append("")
#
#                     if result['total_changes'] > 0 and 'changes' in result and result['changes']:
#                         report_lines.append("更改详情:")
#                         report_lines.append("-" * 60)
#
#                         for change in result['changes']:
#                             report_lines.append(f"行 {change.line}: '{change.original}' -> '{change.fixed}'")
#                             report_lines.append(f"上下文: {change.context}")
#                             report_lines.append("")
#
#                         report_lines.append("-" * 60)
#                         report_lines.append("")
#
#         report = "\n".join(report_lines)
#
#         if report_file:
#             with open(report_file, 'w', encoding='utf-8') as f:
#                 f.write(report)
#             self.logger.info(f"报告已保存到: {report_file}")
#
#         return report
#
#
# def main():
#     """命令行入口点"""
#     parser = argparse.ArgumentParser(description='中英文混合LaTeX文档标点符号修复工具')
#
#     # 输入/输出参数
#     parser.add_argument('files', nargs='+', help='输入文件路径(支持通配符)')
#     parser.add_argument('-o', '--output-dir', help='输出文件目录')
#     parser.add_argument('-r', '--report', help='生成报告文件路径')
#     parser.add_argument('--report-format', choices=['text', 'markdown', 'json'], default='text',
#                         help='报告格式(text, markdown, json)')
#
#     # 操作选项
#     parser.add_argument('-p', '--preview', action='store_true', help='仅预览更改，不修改文件')
#     parser.add_argument('-b', '--no-backup', action='store_true', help='不创建备份文件')
#     parser.add_argument('-c', '--config', help='配置文件路径')
#
#     # 日志选项
#     parser.add_argument('--verbose', action='store_true', help='输出详细日志信息')
#     parser.add_argument('--quiet', action='store_true', help='只输出错误信息')
#
#     args = parser.parse_args()
#
#     # 设置日志级别
#     log_level = logging.INFO
#     if args.verbose:
#         log_level = logging.DEBUG
#     elif args.quiet:
#         log_level = logging.ERROR
#
#     logging.basicConfig(level=log_level,
#                         format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
#
#     logger = logging.getLogger(__name__)
#
#     # 创建标点修复器
#     fixer = PunctuationFixer(config_file=args.config)
#
#     # 扩展文件通配符
#     import glob
#     input_files = []
#     for file_pattern in args.files:
#         matched_files = glob.glob(file_pattern)
#         if matched_files:
#             input_files.extend(matched_files)
#         else:
#             logger.warning(f"没有找到匹配的文件: {file_pattern}")
#
#     if not input_files:
#         logger.error("没有找到匹配的文件")
#         return 1
#
#     # 确保输出目录存在
#     if args.output_dir and not os.path.exists(args.output_dir):
#         os.makedirs(args.output_dir)
#
#     # 处理文件
#     results = fixer.process_files(
#         input_files,
#         output_dir=args.output_dir,
#         backup=not args.no_backup,
#         preview_only=args.preview
#     )
#
#     # 生成报告
#     if args.report:
#         report = fixer.generate_report(results, args.report, args.report_format)
#     else:
#         report = fixer.generate_report(results, format=args.report_format)
#         print(report)
#
#     logger.info(f"处理完成，共处理 {len(input_files)} 个文件")
#     return 0
#
#
# if __name__ == "__main__":
#     exit(main())